/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 7/8/2010
 * Time: 10:03 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using popLib;
using Microsoft.Win32;
using System.IO;
using System.Collections;
using System.Collections.Generic;

namespace FileAssociateManager
{
	/// <summary>
	/// Description of Global.
	/// </summary>
	public class Global
	{
		static Global _global;
		DataSet data = DataLib.initDataSet(" Types[ #Type, Icon ] \r\n Commands[ Type, Default, Shell, Command, Application, FullPath ] ");
		string datafile = FileLib.getFullPath("data.dat");
		
		public Global(){
			LoadData();
		}
		
		public static Global Instance(){
			if( _global == null )
				_global = new Global();
			return _global;
		}
		
		public DataSet Data{
			get{ return data; }
			set{ data = value; }
		}
		
		public void LoadData(){
			if( File.Exists(datafile) )
				data.ReadXml( datafile );
		}
		
		public void SaveDate(){
			data.WriteXml( datafile );
		}
		
		#region Handle extension
		public void AddOrUpdateExtension(Extension extension){
			
			DataRow row = Data.Tables[0].Rows.Find(extension.Type);
			if( row == null ){
				row = Data.Tables[0].NewRow();
				row["Type"] = extension.Type;
				row["Icon"] = extension.Icon;
				Data.Tables[0].Rows.Add( row );
			}else{
				row["Type"] = extension.Type;
				row["Icon"] = extension.Icon;
			}
			
			AddExtensionCommand( extension.Type, extension.ShellCommands );
			
			SaveDate();
		}
		
		private void AddExtensionCommand(string type, List<ExtensionCommand> extensionCommands){
			
			//remove all current commands
			DataRow[] currentExtensionCommands = Data.Tables[1].Select( "Type = '"+type+"'" );
			foreach( DataRow row in currentExtensionCommands )
				Data.Tables[1].Rows.Remove( row );
			
			//insert new commands
			foreach( ExtensionCommand command in extensionCommands ){
				Data.Tables[1].Rows.Add( new object[]{ 
				                        	command.Type, 
				                        	command.Default, 
				                        	command.Shell, 
				                        	command.Command, 
				                        	command.Application, 
				                        	command.FullPath
				                        });
			}
		}
		
		public ReturnSet LoadExtension( string type ){
			Extension extension = new Extension( type, "", new List<ExtensionCommand>() );
			
			DataRow extensionRow = Data.Tables[0].Rows.Find(extension.Type);
			if( extensionRow == null ) return new ReturnSet( false, null, "File type ["+extension.Type+"] is not existed!!" );
			extension.Icon = extensionRow[1].ToString();
			
			DataRow[] commandRows = Data.Tables[1].Select( "Type = '"+type+"'" );
			
			foreach( DataRow row in commandRows ){
				extension.ShellCommands.Add(
					new ExtensionCommand( row["Type"].ToString(),
					                     Convert.ToBoolean(row["Default"]),
					                     row["Shell"].ToString(),
					                     row["Command"].ToString(),
					                     row["FullPath"].ToString()
					                    )
				);
			}
			
			return new ReturnSet( true, extension );
			
		}
		
		public void RemoveExtension(string type){
			//remove extension
			DataRow extensionRow = Data.Tables[0].Rows.Find(type);
			if( extensionRow != null )
				Data.Tables[0].Rows.Remove( extensionRow );
			
			//remove all current commands
			DataRow[] currentExtensionCommands = Data.Tables[1].Select( "Type = '"+type+"'" );
			foreach( DataRow row in currentExtensionCommands )
				Data.Tables[1].Rows.Remove( row );
			
			SaveDate();
		}
		#endregion
						
		#region Type handle functions
		
		/// <summary>
		/// Apply all file type in database
		/// </summary>
		public void ApplyFileType(){
			foreach( DataRow row in data.Tables["Types"].Rows ){
				ReturnSet rs = LoadExtension( row["Type"].ToString() );
				if( rs.Success )
					ApplyFileType( (Extension)rs.Result );
			}
		}
		
		/// <summary>
		/// Apply a file type 
		/// </summary>
		/// <param name="extension">begin with dot such as: .abc .txt .doc</param>
		public void ApplyFileType(string type){			
			ReturnSet rs = LoadExtension( type );
			if( rs.Success )
					ApplyFileType( (Extension)rs.Result );			
		}		
				
		/// <summary>
		/// Apply a file type 
		/// </summary>
		/// <param name="extension">begin with dot such as: .abc .txt .doc</param>
		public void ApplyFileType( Extension extension ){
									
			//remove file type first
			RemoveFileType( extension.RegType );
			
			//create file type first
			RegistryKey type = Registry.ClassesRoot.CreateSubKey( extension.RegType );
			type.SetValue( "" , extension.RegCommandName );
			type.CreateSubKey( "OpenWithList" );
			
			//create handler commands set
			RegistryKey handler = Registry.ClassesRoot.OpenSubKey( extension.RegCommandName );
			if( handler != null ) Registry.ClassesRoot.DeleteSubKeyTree( extension.RegCommandName );
			handler = Registry.ClassesRoot.CreateSubKey( extension.RegCommandName );
			handler.SetValue( "EditFlags", 00000000, RegistryValueKind.DWord );
			handler.SetValue( "BrowserFlags", 00000008, RegistryValueKind.DWord );
						
			//set icon for this type
			string iconFile = extension.Icon;
			RegistryKey icon = handler.CreateSubKey( "DefaultIcon" );
			icon.SetValue( "", iconFile );
									
			//create default command for this type
			RegistryKey shell = handler.CreateSubKey( "shell" );
			shell.SetValue( "", extension.DefaultCommand );
			
			
			//create shell command for this type
			foreach( ExtensionCommand extensionCommand in extension.ShellCommands ){				
				RegistryKey command = handler.CreateSubKey( "shell\\"+extensionCommand.Shell+"\\command" );
				command.SetValue( "", extensionCommand.ShellCommand );
			}
		}
		
		/// <summary>
		/// Remove file type from registry
		/// </summary>
		/// <param name="extension">begin with dot such as: .abc .txt .doc</param>
		public void RemoveFileType( string extension ){
			if( !extension.StartsWith(".") ) extension = "." + extension;
			RegistryKey type = Registry.ClassesRoot.OpenSubKey( extension );
			if( type == null ) return;
			
			if( type.ValueCount > 0 ){	
				string commandSetName;
				try{
					commandSetName = type.GetValue( "" ).ToString();
				}catch{
					return;
				}
				RegistryKey commandSet = Registry.ClassesRoot.OpenSubKey( commandSetName );
				if( commandSet != null )
					Registry.ClassesRoot.DeleteSubKeyTree( commandSetName );
			}
			
			Registry.ClassesRoot.DeleteSubKeyTree( extension );
			
			
			
		}
		
		
		#endregion
			
	}
	
	public class Extension{
		public Extension(string type, string icon, List<ExtensionCommand> shellCommands){
			this.Type = type;
			this.Icon = icon;
			this.ShellCommands = shellCommands;
		}
		
		private string _Type;
		public string Type{ get{return _Type; } set{_Type = value.Replace(".","").Trim().ToUpper();} }
		
		private string _Icon;
		public string Icon{ get{return _Icon;} set{_Icon = value;} }
		
		//get key type in registry from Type, DOC -> .doc
		public string RegType{ get{return "."+Type.ToLower();} }
		
		//get key command type in registry from Type, DOC -> FT-DOC
		public string RegCommandName{ get{return string.Format( "FT-{0}",Type);} }
		
		public string DefaultCommand{ 
			get{ 
				foreach( ExtensionCommand command in ShellCommands ){
					if( command.Default ) return command.Shell;
				}
				if( ShellCommands.Count > 0 ) return ShellCommands[0].Shell;
				return "open";
			}
		}
		
		private List<ExtensionCommand> _ShellCommands;
		public List<ExtensionCommand> ShellCommands{ get{return _ShellCommands;} set{_ShellCommands = value;} }
	}
	
	public class ExtensionCommand
	{		
		public ExtensionCommand(string type, bool isdefault, string shell, string command, string fullpath){
			this.Type = type;
			this.Default = isdefault;
			this.Shell = shell;
			this.Command = command;			
			this.FullPath = fullpath;
			this.Application = System.IO.Path.GetFileNameWithoutExtension(FullPath);
		}
		
		private string _Type;
		public string Type{ get{return _Type;} set{_Type = value;} }

		private bool _Default;
		public bool Default{ get{return _Default;} set{_Default = value;} }

		private string _Shell;
		public string Shell{ get{return _Shell;} set{_Shell = value;} }

		private string _Command;
		public string Command{ get{return _Command;} set{_Command = value;} }

		private string _Application;
		public string Application{ get{return _Application;} set{_Application = value;} }

		private string _FullPath;
		public string FullPath{ get{return _FullPath;} set{_FullPath = value;} }
		
		//something like [APP] "%1"
		public string ShellCommand{
			get{
				return Command.Replace("[APP]", "\""+FullPath+"\"");
			}
		}


	}
}
